#include "gd32w51x.h"
#include "stdio.h"
#include "stdint.h"
#include "DevicesCRC.h"


void vHardCRCInit(void)
{
    /* CRC Peripheral clock enable */
    rcu_periph_clock_enable(RCU_CRC);
}

void vHardCRCReset(void)
{
    /* reset the CRC data register and calculate the CRC of the value */
    crc_data_register_reset();
}

uint32_t uiHardCRCAccumulate(uint32_t *puiDataBuff, int32_t iLength)
{
    uint32_t uiCRC32Value = 0;

    if(puiDataBuff == NULL)
        return 0;

    while((iLength--) > 0)
        uiCRC32Value = crc_single_data_calculate(*puiDataBuff++);

    return uiCRC32Value;
}






uint8_t ucCRC7_MMC(uint8_t *pucInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint8_t ucPolynomial = 0x12, ucInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pucInitCRC != NULL)
        ucInputCRC = *pucInitCRC;

    while((iLength--) > 0)
    {
        ucInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (ucInputCRC & 0x80)
                ucInputCRC = (ucInputCRC << 1) ^ ucPolynomial;
            else
                ucInputCRC <<= 1;
        }
    }

    return ucInputCRC >> 1;
}

uint8_t ucCRC8(uint8_t *pucInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint8_t ucPolynomial = 0x07, ucInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pucInitCRC != NULL)
        ucInputCRC = *pucInitCRC;

    while((iLength--) > 0)
    {
        ucInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (ucInputCRC & 0x80)
                ucInputCRC = (ucInputCRC << 1) ^ ucPolynomial;
            else
                ucInputCRC <<= 1;
        }
    }

    return ucInputCRC;
}

uint8_t ucCRC8_ITU(uint8_t *pucInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint8_t ucPolynomial = 0x07, ucInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pucInitCRC != NULL)
        ucInputCRC = *pucInitCRC;

    while((iLength--) > 0)
    {
        ucInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (ucInputCRC & 0x80)
                ucInputCRC = (ucInputCRC << 1) ^ ucPolynomial;
            else
                ucInputCRC <<= 1;
        }
    }

    return ucInputCRC ^ 0x55;
}

uint8_t ucCRC8_ROHC(uint8_t *pucInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint8_t ucPolynomial = 0xE0, ucInputCRC = 0xFF;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pucInitCRC != NULL)
        ucInputCRC = *pucInitCRC;

    while((iLength--) > 0)
    {
        ucInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (ucInputCRC & 1)
                ucInputCRC = (ucInputCRC >> 1) ^ ucPolynomial;
            else
                ucInputCRC >>= 1;
        }
    }

    return ucInputCRC;
}

uint8_t ucCRC8_MAXIM(uint8_t *pucInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint8_t ucPolynomial = 0x8C, ucInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pucInitCRC != NULL)
        ucInputCRC = *pucInitCRC;

    while((iLength--) > 0)
    {
        ucInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (ucInputCRC & 1)
                ucInputCRC = (ucInputCRC >> 1) ^ ucPolynomial;
            else
                ucInputCRC >>= 1;
        }
    }

    return ucInputCRC;
}




uint16_t usCRC16_IBM(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0xA001, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return usInputCRC;
}

uint16_t usCRC16_MAXIM(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0xA001, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return ~usInputCRC;
}

uint16_t usCRC16_USB(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0xA001, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return ~usInputCRC;
}

uint16_t usCRC16_MODBUS(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0xA001, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return usInputCRC;
}

uint16_t usCRC16_CCITT(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0x8408, usInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return usInputCRC;
}

uint16_t usCRC16_CCITT_FALSE(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0x1021, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= (uint16_t)(*pucDataBuff++) << 8;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 0x8000)
                usInputCRC = (usInputCRC << 1) ^ usPolynomial;
            else
                usInputCRC <<= 1;
        }
    }

    return usInputCRC;
}

uint16_t usCRC16_X25(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0x8408, usInputCRC = 0xffff;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return ~usInputCRC;
}

uint16_t usCRC16_XMODEM(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0x1021, usInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= (uint16_t)(*pucDataBuff++) << 8;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 0x8000)
                usInputCRC = (usInputCRC << 1) ^ usPolynomial;
            else
                usInputCRC <<= 1;
        }
    }

    return usInputCRC;
}

uint16_t usCRC16_DNP(uint16_t *pusInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint16_t usPolynomial = 0xA6BC, usInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(pusInitCRC != NULL)
        usInputCRC = *pusInitCRC;

    while((iLength--) > 0)
    {
        usInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if (usInputCRC & 1)
                usInputCRC = (usInputCRC >> 1) ^ usPolynomial;
            else
                usInputCRC >>= 1;
        }
    }

    return ~usInputCRC;
}




uint32_t uiReflect(uint32_t uiData, uint8_t ucLength)
{
    uint32_t uiMask = 1 << (ucLength - 1), uiMaskRef = 1, uiDataReturn = 0;

    for(; uiMask; uiMask >>= 1)
    {
        if(uiData & uiMask)
            uiDataReturn |= uiMaskRef;

        uiMaskRef <<= 1;
    }

    return uiDataReturn;
}

uint32_t uiCRC32(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0xFFFFFFFF;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    uiPolynomial = uiReflect(uiPolynomial, 32);

    while((iLength--) > 0)
    {
        uiInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if(uiInputCRC & 1)
                uiInputCRC = (uiInputCRC >> 1) ^ uiPolynomial;
            else
                uiInputCRC >>= 1;
        }
    }

    return ~uiInputCRC;
}

uint32_t uiCRC32_BZIP2(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0xFFFFFFFF;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    while((iLength--) > 0)
    {
        uiInputCRC ^= (uint32_t)(*pucDataBuff++) << 24;

        for(i = 0; i < 8; ++i)
        {
            if(uiInputCRC & 0x80000000)
                uiInputCRC = (uiInputCRC << 1) ^ uiPolynomial;
            else
                uiInputCRC <<= 1;
        }
    }

    return ~uiInputCRC;
}

uint32_t uiCRC32_MPEG2(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0xFFFFFFFF;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    while((iLength--) > 0)
    {
        uiInputCRC ^= (uint32_t)(*pucDataBuff++) << 24;

        for(i = 0; i < 8; ++i)
        {
            if(uiInputCRC & 0x80000000)
                uiInputCRC = (uiInputCRC << 1) ^ uiPolynomial;
            else
                uiInputCRC <<= 1;
        }
    }

    return uiInputCRC;
}

uint32_t uiCRC32_POSIX(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    while((iLength--) > 0)
    {
        uiInputCRC ^= (uint32_t)(*pucDataBuff++) << 24;

        for(i = 0; i < 8; ++i)
        {
            if(uiInputCRC & 0x80000000)
                uiInputCRC = (uiInputCRC << 1) ^ uiPolynomial;
            else
                uiInputCRC <<= 1;
        }
    }

    return ~uiInputCRC;
}

uint32_t uiCRC32_JAMCRC(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint8_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0xFFFFFFFF;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    uiPolynomial = uiReflect(uiPolynomial, 32);

    while((iLength--) > 0)
    {
        uiInputCRC ^= *pucDataBuff++;

        for(i = 0; i < 8; ++i)
        {
            if(uiInputCRC & 1)
                uiInputCRC = (uiInputCRC >> 1) ^ uiPolynomial;
            else
                uiInputCRC >>= 1;
        }
    }

    return uiInputCRC;
}

uint32_t uiCRC32_STM32(uint32_t *puiInitCRC, void *pvBuff, int32_t iLength)
{
    uint32_t *pucDataBuff = pvBuff;
    uint32_t uiPolynomial = 0x04C11DB7, uiInputCRC = 0xFFFFFFFF, xbit = 0x80000000, uiDataTemp = 0;
    int8_t i = 0;

    if(pucDataBuff == NULL)
        return 0;

    if(puiInitCRC != NULL)
        uiInputCRC = *puiInitCRC;

    while((iLength--) > 0)
    {
        uiDataTemp = *pucDataBuff++;
        xbit = 0x80000000;

        for(i = 0; i < 32; ++i)
        {
            if(uiInputCRC & 0x80000000)
                uiInputCRC = (uiInputCRC << 1) ^ uiPolynomial;
            else
                uiInputCRC <<= 1;

            if(uiDataTemp & xbit)
                uiInputCRC ^= uiPolynomial;

            xbit >>= 1;
        }
    }

    return uiInputCRC;
}
